package com.jeeww.core.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

/**
 * JSON工具类.
 * @author jiangww
 */
public class JsonUtils {
    /**
     * 每页记录条数.
     */
    public static final String ENTITY_PACKAGE = "com.agile";

    /**
     * 将实体类转换为JSONObject,不转换实体内的一对多多对一.
     * @param entityObj entityObj.
     * @return JSONObject JSONObject
     * @throws Exception e
     */
    public static JSONObject entity2SimpleJSONObject(final Object entityObj) throws Exception {
        JSONObject entityJsonObjValues = new JSONObject();
        Class<?> clazz = entityObj.getClass();
        Field[] fields = clazz.getDeclaredFields(); // 根据Class对象获得属性 私有的也可以获得
        Field.setAccessible(fields, true);
        for (Field f : fields) {
            String fieldName = f.getType().getName();
            if ("serialVersionUID".equals(f.getName())) {
                continue;
            }
            if (fieldName.contains(ENTITY_PACKAGE)) { // 此field是类
                continue;
            } else if (fieldName.contains("java.util.Set")) { // 此field是set
                continue;
            } else {
                entityJsonObjValues.put(f.getName(), BeanUtils.getProperty(entityObj, f.getName()));
            }
        }
        return entityJsonObjValues;
    }

    /**
     * 通过实体对象获得json对象.
     * @param obj 待转换实体
     * @param type 1:没有表明，仅获得一对一，或多对一关系值.2:有表明，仅获得一对一，或多对一关系值.
     * @return JSONObject JSONObject
     * @throws Exception e
     */
    public static JSONObject entity2JSONObject(final Object obj, final int type) throws Exception {
        Map<String, String> excludeEntity = new HashMap<String, String>();
        Class<?> clazz = obj.getClass();
        excludeEntity.put(clazz.getSimpleName(), clazz.getName());
        JSONObject subJsonObj = null;
        if (type == 1) {
            subJsonObj = entity2JSONObjectNoTableName(clazz, obj, excludeEntity, null);
        } else if (type == 2) {
            subJsonObj = entity2JSONObject(clazz, obj, excludeEntity, null, false);
        }
        return subJsonObj;
    }

    /**
     * 对象转换为json，包含表名.
     * @param clazz 类
     * @param entityData 值对象
     * @param excludeEntity 不转换的对象
     * @param includeEntity 转换的对象
     * @param includeSet 是否转换set
     * @return JSONObject JSONObject
     * @throws Exception Exception
     */
    private static JSONObject entity2JSONObject(final Class<?> clazz, final Object entityData,
            final Map<String, String> excludeEntity, final Map<String, String> includeEntity, final boolean includeSet)
            throws Exception {
        JSONObject entityJsonObj = new JSONObject();
        Field[] fields = clazz.getDeclaredFields(); // 根据Class对象获得属性 私有的也可以获得
        Field.setAccessible(fields, true);
        for (Field f : fields) {
            String fieldName = f.getType().getName();
            if ("serialVersionUID".equals(f.getName())) {
                continue;
            }
            if (fieldName.contains(ENTITY_PACKAGE)) { // 此field是类
                String tempName = f.getType().getSimpleName();
                String methodName = "get" + tempName;
                Object objx = invoke(methodName, clazz, entityData);
                if (objx == null) {
                    continue;
                }
                Class<?> subClass = Class.forName(objx.getClass().getName().split("_")[0]);
                String oldEntity = excludeEntity.get(subClass.getSimpleName());
                if (oldEntity != null && oldEntity.equals(subClass.getName())) {
                    continue;
                }
                excludeEntity.put(subClass.getSimpleName(), subClass.getName());
                if (includeEntity == null) {
                    JSONObject subJsonObj = entity2JSONObject(subClass, objx, excludeEntity, null, includeSet);
                    entityJsonObj.put(subClass.getSimpleName(), subJsonObj);
                } else {
                    if (includeEntity.containsKey(subClass.getSimpleName())) {
                        JSONObject subJsonObj = entity2JSONObject(subClass, objx, excludeEntity, includeEntity,
                                includeSet);
                        entityJsonObj.put(subClass.getSimpleName(), subJsonObj);
                    }
                }
            } else if (fieldName.contains("java.util.Set")) { // 此field是set
                if (includeSet) {
                    JSONArray subJsonArray = new JSONArray();
                    String objName = f.getName();
                    String methodName = "get" + objName.substring(0, 1).toUpperCase() + objName.substring(1);
                    Set<?> subEntitiesSet = (Set<?>) invoke(methodName, clazz, entityData);
                    Iterator<?> it = subEntitiesSet.iterator();
                    while (it.hasNext()) {
                        Object entity = it.next();
                        Class<?> subClass = Class.forName(entity.getClass().getName().split("_")[0]);
                        String oldEntity = excludeEntity.get(subClass.getSimpleName());
                        String oldEntitySet = excludeEntity.get(subClass.getSimpleName() + "set");
                        if (oldEntity != null && oldEntity.equals(subClass.getName()) && oldEntitySet == null) {
                            continue;
                        }
                        if (includeEntity == null) {
                            JSONObject subJson = entity2JSONObject(subClass, entity, excludeEntity, null, includeSet);
                            subJsonArray.add(subJson);
                        } else {
                            if (includeEntity.containsKey(subClass.getSimpleName())) {
                                JSONObject subJsonObj = entity2JSONObject(subClass, entity, excludeEntity,
                                        includeEntity, includeSet);
                                subJsonArray.add(subJsonObj);
                            }
                        }
                        excludeEntity.put(subClass.getSimpleName() + "set", subClass.getName());
                        excludeEntity.put(subClass.getSimpleName(), subClass.getName());
                    }
                    if (subJsonArray.size() > 0) {
                        entityJsonObj.put(objName, subJsonArray);
                    }
                }
            } else {
                entityJsonObj.put(f.getName(), BeanUtils.getProperty(entityData, f.getName()));
            }
        }
        return entityJsonObj;
    }

    /**
     * 对象转换为json，不包含表名.
     * @param clazz 类
     * @param entityData 值对象
     * @param excludeEntity 不转换的对象
     * @param includeEntity 转换的对象
     * @return JSONObject JSONObject
     * @throws Exception Exception
     */
    private static JSONObject entity2JSONObjectNoTableName(final Class<?> clazz, final Object entityData,
            final Map<String, String> excludeEntity, final Map<String, String> includeEntity) throws Exception {
        JSONObject entityJsonObj = new JSONObject();
        Field[] fields = clazz.getDeclaredFields(); // 根据Class对象获得属性 私有的也可以获得
        Field.setAccessible(fields, true);
        for (Field f : fields) {
            String fieldName = f.getType().getName();
            if ("serialVersionUID".equals(f.getName())) {
                continue;
            }
            if (fieldName.contains(ENTITY_PACKAGE)) { // 此field是类
                String tempName = f.getType().getSimpleName();
                String methodName = "get" + tempName;
                Object objx = invoke(methodName, clazz, entityData);
                if (objx == null) {
                    continue;
                }
                Class<?> subClass = Class.forName(objx.getClass().getName().split("_")[0]);
                String oldEntity = excludeEntity.get(subClass.getSimpleName());
                if (oldEntity != null && oldEntity.equals(subClass.getName())) {
                    continue;
                }
                excludeEntity.put(subClass.getSimpleName(), subClass.getName());
                if (includeEntity == null) {
                    JSONObject subJsonObj = entity2JSONObjectNoTableName(subClass, objx, excludeEntity, null);
                    entityJsonObj.putAll(subJsonObj);
                } else {
                    if (includeEntity.containsKey(subClass.getSimpleName())) {
                        JSONObject subJsonObj = entity2JSONObjectNoTableName(subClass, objx, excludeEntity,
                                includeEntity);
                        entityJsonObj.putAll(subJsonObj);
                    }
                }
            } else if (fieldName.contains("java.util.Set")) { // 此field是set
                continue;
            } else {
                entityJsonObj.put(f.getName(), BeanUtils.getProperty(entityData, f.getName()));
            }
        }
        return entityJsonObj;
    }

    /**
     * 将集合(实体类)转换为JSONObject,不转换实体内的一对多多对一.
     * @param list list.
     * @return JSONArray JSONArray
     * @throws Exception e
     */
    public static JSONArray list2SimpleJSONArray(final List<?> list) throws Exception {
        JSONArray jsonArray = new JSONArray();
        for (int i = 0; i < list.size(); i++) {
            JSONObject entityJsonObjValues = new JSONObject();
            if (list.get(i) instanceof Object[]) {
                Object[] obj = (Object[]) list.get(i);
                for (int j = 0; j < obj.length; j++) {
                    Object entityObj = obj[j];
                    JSONObject objx = entity2JSONObject(entityObj, 1);
                    entityJsonObjValues.putAll(objx);
                }
            } else if (list.get(i) instanceof HashMap) {
                Object entityObj = list.get(i);
                JSONObject objx = (JSONObject) JSONObject.toJSON(entityObj);
                entityJsonObjValues.putAll(objx);
            } else {
                Object entityObj = list.get(i);
                JSONObject objx = entity2JSONObject(entityObj, 1);
                entityJsonObjValues.putAll(objx);
            }
            jsonArray.add(entityJsonObjValues);
        }
        return jsonArray;
    }

    /**
     * 集合转换为JSONArray.
     * @param list 待转换的集合，集合中是实体对象.
     * @param type 1:无表名，仅转换一对一，多对一. 2:有表名，仅转换一对一，多对一.
     * @return 返回转换后的结果.
     * @throws Exception 异常
     */
    public static JSONArray list2JSONArray(final List<?> list, final int type) throws Exception {
        JSONArray jsonArray = new JSONArray();
        for (int i = 0; i < list.size(); i++) {
            Map<String, String> excludeEntity = new HashMap<String, String>();
            Object obj = list.get(i);
            Class<?> clazz = obj.getClass();
            excludeEntity.put(clazz.getSimpleName(), clazz.getName());
            if (type == 1) {
                JSONObject subJsonObj = entity2JSONObject(obj, 1);
                jsonArray.add(subJsonObj);
            } else if (type == 2) {
                JSONObject subJsonObj = entity2JSONObject(clazz, obj, excludeEntity, null, false);
                JSONObject entityJsonObj = new JSONObject();
                entityJsonObj.put(clazz.getSimpleName(), subJsonObj);
                jsonArray.add(entityJsonObj);
            }
        }
        return jsonArray;
    }

    /**
     * 无表名，转换指定的一些对象.
     * @param list 要转换的集合.
     * @param includeEntity 转换关联的实体对象.
     * @return JSONArray 转换后的结果.
     * @throws Exception 异常.
     */
    public static JSONArray list2JSONArray(final List<?> list, final Map<String, String> includeEntity)
            throws Exception {
        JSONArray jsonArray = new JSONArray();
        for (int i = 0; i < list.size(); i++) {
            Map<String, String> excludeEntity = new HashMap<String, String>();
            Object obj = list.get(i);
            // 形如 SELECT ENTITY_A,ENTITY_B FROM ENTITY_A,ENTITY_B 的查询在此需要扩展。
            if (obj instanceof Object[]) {
                Object[] objs = (Object[]) obj;
                JSONObject subJsonObj = new JSONObject();
                for (int j = 0; j < objs.length; j++) {
                    Class<?> clazz = objs[j].getClass();
                    excludeEntity.put(clazz.getSimpleName(), clazz.getName());
                    JSONObject oneSubJsonObj = entity2JSONObjectNoTableName(clazz, obj, excludeEntity, includeEntity);
                    subJsonObj.putAll(oneSubJsonObj);
                }
                jsonArray.add(subJsonObj);
            } else {
                Class<?> clazz = obj.getClass();
                excludeEntity.put(clazz.getSimpleName(), clazz.getName());
                JSONObject subJsonObj = entity2JSONObjectNoTableName(clazz, obj, excludeEntity, includeEntity);
                jsonArray.add(subJsonObj);
            }
        }
        return jsonArray;
    }

    /**
     * 无表名，转换指定的一些对象.
     * @param list 要转换的集合.
     * @param includeEntity 转换关联的实体对象.
     * @return JSONArray 转换后的结果.
     * @throws Exception 异常.
     */
    public static JSONArray list2JSONArrayInclude(final List<?> list, final Map<String, String> includeEntity)
            throws Exception {
        JSONArray jsonArray = new JSONArray();
        for (int i = 0; i < list.size(); i++) {
            Map<String, String> excludeEntity = new HashMap<String, String>();
            JSONObject entityJsonObj = new JSONObject();
            Object obj = list.get(i);
            Class<?> clazz = obj.getClass();
            excludeEntity.put(clazz.getSimpleName(), clazz.getName());
            JSONObject subJsonObj = entity2JSONObject(clazz, obj, excludeEntity, includeEntity, true);
            entityJsonObj.put(clazz.getSimpleName(), subJsonObj);
            jsonArray.add(entityJsonObj);
        }
        return jsonArray;
    }

    /**
     * 无表名，转换指定的一些对象.
     * @param list 要转换的集合.
     * @param excludeEntity 不转换此参数内关联的实体对象.
     * @return JSONArray 转换后的结果.
     * @throws Exception 异常.
     */
    public static JSONArray list2JSONArrayExclude(final List<?> list, final Map<String, String> excludeEntity)
            throws Exception {
        JSONArray jsonArray = new JSONArray();
        for (int i = 0; i < list.size(); i++) {
            Map<String, String> excludeEntityRuntime = new HashMap<String, String>();
            excludeEntityRuntime.putAll(excludeEntity);
            JSONObject entityJsonObj = new JSONObject();
            Object obj = list.get(i);
            Class<?> clazz = obj.getClass();
            excludeEntityRuntime.put(clazz.getSimpleName(), clazz.getName());
            JSONObject subJsonObj = entity2JSONObject(clazz, obj, excludeEntityRuntime, null, true);
            entityJsonObj.put(clazz.getSimpleName(), subJsonObj);
            jsonArray.add(entityJsonObj);
        }
        return jsonArray;
    }

    /**
     * 反射回调.
     * @param methodName 方法名称.
     * @param clazz 类.
     * @param obj 对象
     * @return 返回对象.
     * @throws Exception 异常.
     */
    public static Object invoke(final String methodName, final Class<?> clazz, final Object obj) throws Exception {
        Class<?>[] params = null;
        Method m = clazz.getMethod(methodName, params);
        Object[] paramsi = null;
        Object objx = m.invoke(obj, paramsi);
        return objx;
    }
}
